grammar Script;

import CommonLexer;

name: IDENTIFIER;

variableDeclarators
    : variableDeclarator (',' variableDeclarator)*
    ;

variableDeclarator
    : variableDeclaratorId ('=' variableInitializer)?
    ;

variableDeclaratorId
    : name ('[' ']')*
    ;

variableInitializer
    : arrayInitializer
    | jsonInitializer
    | expression
    ;


arrayInitializer
    : '[' (variableInitializer (',' variableInitializer)* (',')? )? ']'
    ;

jsonInitializer
   : jsonValue
   ;

jsonArr
   : '[' jsonValue (',' jsonValue)* ']'
   | '[' ']'
   ;

jsonObj
   : '{' jsonPair (',' jsonPair)* '}'
   | '{' '}'
   ;

jsonPair
   : STRING_LITERAL ':' jsonValue
   ;

jsonValue
   : STRING_LITERAL
   | literal
   | jsonObj
   | jsonArr
   ;

literal
    : DECIMAL_LITERAL
    | FLOAT_LITERAL
    | STRING_LITERAL
    | BOOL_LITERAL
    | NULL_LITERAL
    ;

classDeclaration
    : CLASS name
      classBody
    ;

classBody
    : '{' classBodyDeclaration* '}'
    ;

classBodyDeclaration
       : functionDeclaration
       | fieldDeclaration
       | classDeclaration
       ;

functionDeclaration
    : FUNCTION name formalParameters
      functionBody
    ;

functionBody
    : block
    | ';'
    ;

formalParameters
    : '(' formalParameterList? ')'
    ;

formalParameterList
    : variableDeclaratorId (',' variableDeclaratorId)*
    ;

fieldDeclaration
    : variableDeclarators ';'
    ;

prog
    : blockStatements
    ;

block
    : '{' blockStatements '}'
    ;

blockStatements
    : blockStatement*
    ;

blockStatement
    : variableDeclarators ';'
    | statement
    | functionDeclaration
    | classDeclaration
    ;

statement
    : block
    | IF parExpression block (ELSE statement)?
    | FOR '(' forControl ')' block
    | WHILE parExpression block
    | RETURN expression? ';'
    | BREAK ';'
    | CONTINUE ';'
    | SEMI
    | statementExpression=expression ';'
    ;


forControl
    : forInit? ';' expression? ';' forUpdate=expressionList?
    ;

forInit
    : variableDeclarators
    | expressionList
    ;

parExpression
    : '(' expression ')'
    ;

expressionList
    : expression (',' expression)*
    ;

functionCall
    : name '(' expressionList? ')'
    ;

expression
    : primary
    | expression bop='.' (name | functionCall)
    | expression '[' expression ']'
    | functionCall
    | expression postfix=('++' | '--')
    | expression bop=('*'|'/'|'%') expression
    | expression bop=('+'|'-') expression 
    | expression bop=('<=' | '>=' | '>' | '<') expression
    | expression bop=('==' | '!=') expression
    | expression bop=('&&' | '||') expression
    | expression bop='?' expression ':' expression
    | <assoc=right> expression bop=('=' | '+=' | '-=' | '*=' | '/=' | '%=') expression
    ;


primary
    : '(' expression ')'
    | literal
    | name
    ;